package org.rslai.tcedit.dao.hibernate;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.rslai.tcedit.dao.EntityTableDao;
import org.rslai.tcedit.exception.ApplicationException;
import org.rslai.tcedit.util.XmlUtil;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.util.FileCopyUtils;

/**
 * EntityTableDao 的实现类
 * 
 * @author rslai
 * 
 * @spring.bean id="entityTableDao"
 */
public class EntityTableImpl implements EntityTableDao {
	protected HibernateTemplate hibernateTemplate;

	private Resource resourceDynamicTable;
	private static String PRODUCT_ID = "\\$\\{productID\\}";
	private String rootPath = "";
	private String domainPath = "/src/org/rslai/tcedit/domain";
	private String domainClassPath = "org.rslai.tcedit.domain.";

	/**
	 * @spring.property name="hibernateTemplate" ref="hibernateTemplate"
	 */
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}

	/**
	 * 设置源代码所在根路径，例如：代码在“C:\TCedit\src\org......”目录在其根路径应设置为“C:\TCedit”
	 * 
	 * @spring.property value=""
	 */
	public void setRootPath(String rootPath) {
		if (rootPath.equals("")) {
			Resource res = new ClassPathResource(getClass().getName().replace('.', '/') + ".class");
			try {
				String currentClassFileName = res.getFile().getPath().replace('\\', '/'); // 得到当前类路径和文件名
				// 得到源代码跟路径
				if (currentClassFileName.indexOf("/web/") != -1 ) {
					this.rootPath = currentClassFileName.substring(0, currentClassFileName.indexOf("/web/"));
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			this.rootPath = rootPath;
		}
	}

	/**
	 * 设置动态数据库表SQL语句文件
	 * 
	 * @spring.property value="/WEB-INF/mysqlDynamicTable.sql"
	 */
	public void setResourceDynamicTable(Resource resourceDynamicTable) {
		this.resourceDynamicTable = resourceDynamicTable;
	}

	public void createEntity(String productID) {
		try {
			createEntityFiles(productID); // 创建domain目录下的实体文件

//			// 修改xml配置文件
//			createServicesConf(productID); // 在Services.xml文件中添加实体名
//			createHibernateConf(productID); // 在hibernate.cfg.xml文件中添加实体名
//		} catch (DocumentException e) {
//			e.printStackTrace();
//			throw new ApplicationException(e.getMessage());
		} catch (IOException e) {
			throw new ApplicationException("源代码domain目录设置错误，请联系系统管理员。<br>" + e.getMessage());
		}
	}

	public void createEntityTable(String productID) {
		try {
			createEntityFiles(productID); // 创建domain目录下的实体文件

//			// 修改xml配置文件
//			createServicesConf(productID); // 在Services.xml文件中添加实体名
//			createHibernateConf(productID); // 在hibernate.cfg.xml文件中添加实体名
			
			createDynamicTable(productID); // 创建动态数据库表
//		} catch (DocumentException e) {
//			e.printStackTrace();
//			throw new ApplicationException(e.getMessage());
		} catch (IOException e) {
			throw new ApplicationException("源代码domain目录设置错误，请联系系统管理员。<br>" + e.getMessage());
		}
	}

	/**
	 * 创建domain目录下的实体文件
	 * @param productID 产品ID
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private void createEntityFiles(String productID) throws FileNotFoundException, IOException {
		copyFile(rootPath + domainPath + "/Catalog.txt", rootPath + domainPath + "/Catalog_" + productID + ".java", productID);
		copyFile(rootPath + domainPath + "/TestCase.txt", rootPath + domainPath + "/TestCase_" + productID + ".java", productID);
		copyFile(rootPath + domainPath + "/TestCaseHistory.txt", rootPath + domainPath + "/TestCaseHistory_" + productID + ".java", productID);
		copyFile(rootPath + domainPath + "/TestCaseModifyNote.txt", rootPath + domainPath + "/TestCaseModifyNote_" + productID + ".java", productID);
		copyFile(rootPath + domainPath + "/TestPlan.txt", rootPath + domainPath + "/TestPlan_" + productID + ".java", productID);
		copyFile(rootPath + domainPath + "/TestCaseExecutant.txt", rootPath + domainPath + "/TestCaseExecutant_" + productID + ".java", productID);
		copyFile(rootPath + domainPath + "/TestResult.txt", rootPath + domainPath + "/TestResult_" + productID + ".java", productID);
	}

	/**
	 * 将指定文件复制到目标位置上，并将指定内容替换为productID（FileSystemResource以文件系统绝对路径的方式进行访问）
	 * @param source 原路径文件
	 * @param destination 目标路径文件
	 * @param productID 产品ID
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private void copyFile(String source, String destination, String productID) throws FileNotFoundException, IOException {
		Resource res = new FileSystemResource(source);
		String fileStr = FileCopyUtils.copyToString(new FileReader(res.getFile()));
		fileStr = fileStr.replaceAll(PRODUCT_ID, productID);
		FileCopyUtils.copy(fileStr.getBytes(), new File(destination));
	}

	/**
	 * 在Services.xml文件中添加实体名
	 * @param productID 产品ID
	 * @throws DocumentException
	 * @throws IOException
	 */
	private void createServicesConf(String productID) throws DocumentException, IOException {
		Resource res = new FileSystemResource(this.rootPath	+ "/conf/services.xml");
		Document doc = new XmlUtil().loadFromXML(res);
		Element root = doc.getRootElement();

		List<?> beanPropertys = root.selectNodes("/*[name()='beans']/*[name()='bean']/*[name()='property']");
		for (Object beanProperty : beanPropertys) {
			String beanPropertyName = ((Element) beanProperty).attributeValue("name");
			if (beanPropertyName!=null && beanPropertyName.equals("annotatedClasses")) {
				Element beanPropertyLists = ((Element) beanProperty).element("list");
				if (!isServicesExistEntity(beanPropertyLists, productID)) {
					beanPropertyLists.addElement("value").setText(domainClassPath + "Catalog_" + productID);
					beanPropertyLists.addElement("value").setText(domainClassPath + "TestCase_" + productID);
				}
			}
		}

		new XmlUtil().writerXML(doc, this.rootPath + "/conf/services.xml");
	}

	/**
	 * 在Services.xml的Element中查找是否存在该productID的实体名
	 * @param element Element
	 * @param productID 产品ID
	 * @return true 存在，false 不存在
	 */
	private boolean isServicesExistEntity(Element element, String productID) {
		for (Iterator<?> valueIter = element.elementIterator("value"); valueIter.hasNext(); ) {
			if (((Element) valueIter.next()).getText().indexOf(productID) != -1) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 在hibernate.cfg.xml文件中添加实体名
	 * @param productID 产品ID
	 * @throws DocumentException
	 * @throws IOException
	 */
	private void createHibernateConf(String productID) throws DocumentException, IOException {
		Resource res = new FileSystemResource(this.rootPath	+ "/conf/unused/hibernate.cfg.xml");
		Document doc = new XmlUtil().loadFromXML(res);
		Element root = doc.getRootElement();

		List<?> sessionFactoryMappings = root.selectNodes("/*[name()='hibernate-configuration']/*[name()='session-factory']/*[name()='mapping']");
		if (!isHibernateCfgExistEntity(sessionFactoryMappings, productID)) {
			List<?> sessionFactory = root.selectNodes("/*[name()='hibernate-configuration']/*[name()='session-factory']");
			((Element) sessionFactory.get(0)).addElement("mapping").addAttribute("class", domainClassPath + "Catalog_" + productID);
			((Element) sessionFactory.get(0)).addElement("mapping").addAttribute("class", domainClassPath + "TestCase_" + productID);
		}

		new XmlUtil().writerXML(doc, this.rootPath + "/conf/unused/hibernate.cfg.xml");
	}

	/**
	 * 在hibernate.cfg.xml的Element中查找是否存在该productID的实体名
	 * @param list Element列表
	 * @param productID 产品ID
	 * @return true 存在，false 不存在
	 */
	private boolean isHibernateCfgExistEntity(List<?> list, String productID) {
		for (Object element : list) {
			String elementClass = ((Element) element).attributeValue("class");
			if (elementClass!=null && elementClass.indexOf(productID)!=-1) {
				return true;
			}
		}
		return false;
	}

    /**
	 * 创建动态数据库表
	 * @param productID 产品ID
     * @throws IOException 
	 */
	private void createDynamicTable(String productID) throws IOException {
		BufferedReader bfReader = new BufferedReader(new InputStreamReader(resourceDynamicTable.getInputStream(), "UTF-8"));

		String str = "";
		String lineStr;
		while ((lineStr = bfReader.readLine()) != null) {
			if (lineStr.toUpperCase().equals("GO")) {
				executeSql(str.replaceAll(PRODUCT_ID, productID));
				str = "";
			} else {
				str = str + lineStr;
				if (lineStr.indexOf("#") == 0) {
					str = str + "\r\n";
				}
			}
		}
	}

	/**
	 * 执行一条sql原语
	 * @param sqlStr sql语句
	 */
	private void executeSql(final String sqlStr) {
		if (sqlStr.trim().length() == 0) {
			return;
		}

		HibernateCallback selectCallback = new HibernateCallback() {
			public Object doInHibernate(Session session) {
				SQLQuery sqlQuery = session.createSQLQuery(sqlStr);
				return sqlQuery.executeUpdate();
			}
		};
		hibernateTemplate.execute(selectCallback);
	}

}
